AddCSLuaFile( "cl_init.lua" ) //dl that
AddCSLuaFile( "shared.lua" ) //dl that too
AddCSLuaFile( "cl_hud.lua" )
AddCSLuaFile( "cl_menu.lua" )
AddCSLuaFile( "cl_base_scoreboard.lua" )
AddCSLuaFile( "cl_mainmenu.lua" )
AddCSLuaFile( "cl_perks.lua" )
AddCSLuaFile( "cl_voicecom.lua" )
AddCSLuaFile( "cl_loadout.lua" )
AddCSLuaFile( "cl_render.lua" )

include( 'shared.lua' )
include( 'menu.lua' )
include( 'perks.lua' )
include( 'voicecom.lua' )
include( 'loadout.lua' )

if not(datastream) then  
    require("datastream");  
end

hook.Add("PlayerDisconnected","remove_render",RemoveRenderObj)

function GM:PlayerSpawn( ply )
    self.BaseClass:PlayerSpawn( ply )
    //ply:SetGravity( 0.75 )  
    //ply:SetMaxHealth( 100, true )  
 
    //ply:SetWalkSpeed( 325 )  
	//ply:SetRunSpeed( 325 )
	ply:SetNetworkedInt("soldierlvl",math.Clamp(ply:GetNWInt("soldierlvl"),1,100))
	ply:SetNetworkedInt("supportlvl",math.Clamp(ply:GetNWInt("supportlvl"),1,100))
	ply:SetNetworkedInt("assassinlvl",math.Clamp(ply:GetNWInt("assassinlvl"),1,100))
	ply:SetNetworkedInt("marksmanlvl",math.Clamp(ply:GetNWInt("marksmanlvl"),1,100))
	if ply:GetNetworkedString("class") == "soldier" then
		ply:SetWalkSpeed( 255 )  
		ply:SetRunSpeed( 255 )
		ply:SetGravity( 1 ) 
		ply:SetArmor(100)
		ply:SetHealth( 100, true )  
	elseif ply:GetNetworkedString("class") == "support" then
		ply:SetWalkSpeed( 255 )  
		ply:SetRunSpeed( 255 )
		ply:SetGravity( 1 ) 
		ply:SetHealth( 100, true )
	elseif ply:GetNetworkedString("class") == "assassin" then
		ply:SetWalkSpeed( 355 )  
		ply:SetRunSpeed( 355 )
		ply:SetGravity( 0.8 ) 
		ply:SetHealth( 50, true )  
		ply:SetNetworkedInt("ClkFired",0)
	elseif ply:GetNetworkedString("class") == "marksman" then
		ply:SetWalkSpeed( 255 )  
		ply:SetRunSpeed( 255 )
		ply:SetGravity( 1 ) 
		ply:SetHealth( 100, true )  
	elseif ply:GetNetworkedString("class") == "spectator" then
		Spectate(ply)
	end
	ply:SetNWInt("maxhealth",ply:Health())
end

function Spectate(ply)
	ply:Spectate( OBS_MODE_ROAMING )
end


BlueSpawnType = {"info_player_combine","info_player_counterterrorist"}
BlueSpawn= {}
RedSpawnType = {"info_player_rebel","info_player_terrorist"}
RedSpawn = {}

timer.Create("addspawns",5,1,function()
	for k,v in pairs(BlueSpawnType) do
		for i,s in pairs(ents.FindByClass(v)) do
			table.insert(BlueSpawn,s)
		end
	end
	print("Blue team's spawns:")
	PrintTable(BlueSpawn)
	print("\n")
	for k,v in pairs(RedSpawnType) do
		for i,s in pairs(ents.FindByClass(v)) do
			table.insert(RedSpawn,s)
		end
	end
	print("Red team's spawns:")
	PrintTable(RedSpawn)
	print("\n")
end)

function GM:PlayerSelectSpawn(ply)
	if team.GetName(ply:Team()) == "Red Team" then return RedSpawn[math.random(1,table.Count(RedSpawn))]
	elseif team.GetName(ply:Team()) == "Blue Team" then return BlueSpawn[math.random(1,table.Count(BlueSpawn))]
	else return ents.FindByClass("info_player_*")[math.random(1,table.Count(ents.FindByClass("info_player_*")))] end
end

function printAction( mssg )
	for k,ply in pairs(player.GetAll()) do
		ply:ChatPrint( mssg )
	end
end

function RandomClass(ply)
	local Classes = {"soldier","support","assassin","soldier"}
	local RClass = Classes[math.random(1,4)]
	print("DM: New player "..ply:Nick().." was randomly assigned to class \""..RClass.."\"!")
	return RClass
end

function GiveTeam(ply)
	local rply = 0
	local bply = 0
	for k,v in pairs(player.GetAll()) do
		if v:Team() == 1 then bply = bply + 1 end
		if v:Team() == 2 then rply = rply + 1 end
	end
	if bply > rply then
		ply:SetTeam(2)
	elseif rply > bply then
		ply:SetTeam(1)
	else
		ply:SetTeam(math.random(1,2))
	end
end

	statnames = {
	"xp",
	"assassinxp",
	"assassinlvl",
	"soldierxp",
	"soldierlvl",
	"supportxp",
	"supportlvl",
	"marksmanxp",
	"marksmanlvl"
	}

AutoAssign = true

concommand.Add("dm_autoassign",function(ply,cmd,args)
	if ply:IsAdmin() then
		if tonumber(args[1]) == 1 then
			AutoAssign = true
			print("DM: autoassign enabled")
		elseif tonumber(args[1]) == 0 then
			AutoAssign = false
			print("DM: autoassign disabled")
		end
	end
end)

function GM:PlayerInitialSpawn( ply )
	
	-- ply:SetTeam(3)  DISABLED FOR TESTING
	ply:Spawn()
	ply:KillSilent()
	ply:SetNetworkedInt("RadFired",0)
	-- ply:SetNWString("class","spectator")  DISABLED FOR TESTING
	ply:ConCommand("dm_classmenu")
	if string.find(string.lower(ply:Nick()),"bot") then
		ply:SetNWString("class",RandomClass(ply))
	end
	if !ply:GetPData("xp") then
		ply:SetNWInt("new",1)
	end
	
	if AutoAssign then
		GiveTeam(ply)
	else
		ply:ConCommand("dm_teamsel")
	end
	
	LoadStats(ply,statnames)
	datastream.StreamToClients(ply, "Weapons", Weapons)
	print("DM: Sending weapon list to player "..ply:Nick())
end

function LoadStats(ply,stats)
	if ply:GetNWInt("new") == 1 then
		sql.Begin()
		for k,v in pairs(stats) do
			ply:SetNWInt(v,0)
			ply:SetPData(v,0)
		end
		ply:SetPData("weapons",glon.encode({}))
		ply.Weapons = {}
		print("DM: Building stats DB for player \""..ply:Nick().."\"")
		sql.Commit()
	else
		for k,v in pairs(stats) do
			ply:SetNWInt(v,tonumber(ply:GetPData(v)))
			print("DM: Loaded stat \""..v.."\" Value: "..ply:GetPData(v).." ("..ply:Nick()..")")
		end
		ply.Weapons = glon.decode(ply:GetPData("weapons"))
		print("DM: Loaded weapon loadouts ("..ply:Nick()..")")
	end
end

function ResetStats(ply,stats)
	sql.Begin()
	for k,v in pairs(stats) do
		ply:SetPData(v,0)
		ply:SetNWInt(v,0)
	end
	ply:SetPData("weapons",glon.encode({}))
	ply.Weapons = {}
	sql.Commit()
	print("DM: Reset "..ply:Nick().."'s stats")
end

function GM:EntityTakeDamage( ent, inflictor, attacker, amount, dmginfo )
	if ent:GetModel()=="models/props_c17/concrete_barrier001a.mdl" or ent:GetModel()=="models/props_lab/reciever_cart.mdl" then
		Checkhealth( ent, inflictor, attacker, amount, dmginfo ) // See perks.lua
	end
end

SQLHasChanged = false

function updateXP(...)
	sql.Begin()
	for k,ply in pairs({...}) do // {...} allows infinite args
		if ply:IsValid() then
			//Total xp
			ply:SetPData("xp",ply:GetNWInt("xp"))
			
			//class levels
			ply:SetPData("assassinlvl",ply:GetNWInt("assassinlvl"))
			ply:SetPData("soldierlvl",ply:GetNWInt("soldierlvl"))
			ply:SetPData("supportlvl",ply:GetNWInt("supportlvl"))
			ply:SetPData("marksmanlvl",ply:GetNWInt("marksmanlvl"))
			
			//Class xp
			ply:SetPData("assassinxp",ply:GetNWInt("assassinxp"))
			ply:SetPData("soldierxp",ply:GetNWInt("soldierxp"))
			ply:SetPData("supportxp",ply:GetNWInt("supportxp"))
			ply:SetPData("marksmanxp",ply:GetNWInt("marksmanxp"))
		end
	end
	sql.Commit()
end 

/*
function RequestSQLCommit()
	if !schedule.IsSchedule("SQLupd") then
		schedule.Add("SQLupd",function()
			sql.Commit()
			schedule.Remove("SQLupd")
			SQLHasChanged = false
			print("DM: Committing SQL database")
		end ,SysTime()+300*60)
	end
end
*/

function GM:PlayerLoadout( ply )
	if !ply:GetNWString("class") then
		return
	end
	if ply:GetNetworkedString("class") != "spectator" and ply:GetNetworkedString("class") != "" then
		if ply.Weapons[string.upper(string.sub(ply:GetNetworkedString("class"),1,1))..string.lower(string.sub(ply:GetNetworkedString("class"),2,99))] then
			for k,v in pairs(ply.Weapons[string.upper(string.sub(ply:GetNetworkedString("class"),1,1))..string.lower(string.sub(ply:GetNetworkedString("class"),2,99))]) do
				ply:Give(v)
				if k == 1 then ply:SelectWeapon(v) end
				ply:GiveAmmo(60,ply:GetActiveWeapon():GetPrimaryAmmoType())
			end
		else
			ply.Weapons[string.upper(string.sub(ply:GetNetworkedString("class"),1,1))..string.lower(string.sub(ply:GetNetworkedString("class"),2,99))] = { [1] = Weapons.Primary[string.upper(string.sub(ply:GetNetworkedString("class"),1,1))..string.lower(string.sub(ply:GetNetworkedString("class"),2,99))][1], [2] = Weapons.Secondary[string.upper(string.sub(ply:GetNetworkedString("class"),1,1))..string.lower(string.sub(ply:GetNetworkedString("class"),2,99))] }
		end
			
	elseif ply:GetNetworkedString("class") != "" then
		ply:ConCommand("dm_loadout "..ply:GetNWString("class"))
		-- ply.Weapons[string.upper(string.sub(ply:GetNetworkedString("class"),1,1))..string.lower(string.sub(ply:GetNetworkedString("class"),2,99))] = { Weapons.Primary[string.upper(string.sub(ply:GetNetworkedString("class"),1,1))..string.lower(string.sub(ply:GetNetworkedString("class"),2,99))][1], Weapons.Secondary[string.upper(string.sub(ply:GetNetworkedString("class"),1,1))..string.lower(string.sub(ply:GetNetworkedString("class"),2,99))] }
		ply:KillSilent()
	else
		ply:KillSilent()
	end
	if ply:GetNWString("class") == "assassin" then
		ply:Give("ass_cloak")
	elseif ply:GetNWString("class") == "soldier" then
		-- none
	elseif ply:GetNWString("class") == "support" then
		ply:Give("sup_barrier")
		ply:Give("med_kit")
	elseif ply:GetNWString("class") == "marksman" then
		ply:Give("mark_radar")
	end
end

function playerDies( victim, weapon, killer )
	if killer:IsValid() and victim:IsValid() and weapon:IsValid() then
	
		victim:ConCommand("dm_killcam " .. killer:EntIndex())

		local XP = 15
		
		if killer:Team() == victim:Team() and killer != victim then 
			XP = -10
			killer:PrintMessage(HUD_PRINTCENTER,"You lost 10 XP due to teamkill!")
			print("DM: "..killer:Nick().." teamkilled "..victim:Nick())
		elseif killer != victim then
			killer:PrintMessage(HUD_PRINTCENTER,"You gained "..XP.." XP!")
		else
			XP = 0
		end
		
		killer:SetNetworkedInt("XP", killer:GetNetworkedInt("XP") + (XP)) 
		killer:SetNWInt(killer:GetNetworkedString("class").."xp",killer:GetNWInt(killer:GetNetworkedString("class").."xp") + XP )
		if killer:GetNWInt(killer:GetNetworkedString("class").."xp") >= (killer:GetNWInt(killer:GetNetworkedString("class").."lvl")*200) then
			killer:SetNWInt(killer:GetNetworkedString("class").."xp", 0)
			killer:SetNWInt(killer:GetNetworkedString("class").."lvl",killer:GetNWInt(killer:GetNetworkedString("class").."lvl")+1)
			killer:PrintMessage(HUD_PRINTCENTER,"You leveled up your skill as an "..killer:GetNetworkedString("class").." to level "..killer:GetNWInt(killer:GetNetworkedString("class").."lvl").."!")
		end
		if killer != victim then
			killer:SetNetworkedInt("lastxp", (XP)) 
			killer:SetNetworkedVector( "lastkill", victim:GetPos()+Vector(0,0,50) )
			killer:ConCommand("dm_xp " .. XP )
		end
		updateXP(victim, killer)
		Uncloak(victim)
		Spectate(victim)
		
		if victim.Stuck then
			if victim.Stuck:IsValid() then
				victim.Stuck:SetParent(nil)
			end
		end
	end
end
 
hook.Add( "PlayerDeath", "playerDeathTest", playerDies );


function ISaid( ply, txt, toall )
	local text = string.lower(txt)
    if (string.sub(text, 1, 3) == "!xp") then
        ply:ChatPrint("You currently have " .. ply:GetNetworkedInt("XP") .. " XP.")
		return ""
    end
	if (string.sub(text, 1, 10) == "!classmenu") then
        ply:ConCommand("dm_classmenu")
		return ""
    end
	if (string.sub(text, 1, 10) == "!mark") then
		if ply:GetNWString("class") == "marksman" then
			ply:ConCommand("dm_marken")
			return ""
		end
    end
	if string.sub(text, 1, 11) == "!resetstats" then
		ResetStats(ply,statnames)
		return ""
	end
	if string.sub(text, 1, 9) == "!teammenu" then
		ply:ConCommand("dm_teamsel")
		return ""
	end
	if string.sub(text, 1, 8) == "!loadout" then
		ply:ConCommand("dm_loadout")
		return ""
	end
	return nil
end
hook.Add( "PlayerSay", "ISaid", ISaid );

function ScaleDamage( ply, hitgroup, dmginfo )
	if dmginfo:GetAttacker():IsPlayer() then
		Uncloak(dmginfo:GetAttacker())
	end
end
 
hook.Add("ScalePlayerDamage","ScaleDamage",ScaleDamage)